package com.example.test1;

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.TextDocumentParser;
import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentByParagraphSplitter;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.onnx.HuggingFaceTokenizer;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.util.List;

@SpringBootTest

public class RAGtest {
    @Test
    /**
     * //文档加载器FileSystemDocumentLoader
     *     //用于从文件系统中加载文档。它支持从文件系统中加载单个文档或多个文档。
     */
    public void testReadDocument() {
        //使用FileSystemDocumentLoader读取指定目录下的知识库文档
        Document document = FileSystemDocumentLoader.loadDocument("C:/Users/wangjj/Desktop/knowledge/测试.txt");
                System.out.println(document.text());
    }
    @Test
    public void testReadDocuments() {
        // 加载单个文档，//并使用默认的文档解析器TextDocumentParser对文档进行解析
        Document document = FileSystemDocumentLoader.loadDocument("C:/Users/wangjj/Desktop/knowledge/file.txt", new TextDocumentParser());
    }

    @Test
    public void testReadFile() {
        // 从一个目录中加载所有文档
        List<Document> documents = FileSystemDocumentLoader.loadDocuments("C:/Users/wangjj/Desktop/knowledge", new TextDocumentParser());
    }

    @Test
    public void testReadFiles() {
        // 从一个目录中加载所有的.txt文档
        PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:*.txt");
        List<Document> documents = FileSystemDocumentLoader.loadDocuments("C:/Users/wangjj/Desktop/knowledge", pathMatcher, new TextDocumentParser());
    }
    @Test
    public void testReadFilesRecursively() {
        // 从一个目录及其子目录中加载所有文档
        List<Document> documents =
                FileSystemDocumentLoader.loadDocumentsRecursively("E:/knowledge", new TextDocumentParser());
    }
    //////////////////////////////////////////////////////

    @Test
    //文档解析器ApachePdfBoxDocumentParser：解析PDF文档
    public void testReadFilesRecursively2() {
        Document document = FileSystemDocumentLoader.loadDocument(
                "C:/Users/wangjj/Desktop/knowledge/医院信息.pdf",
                new ApachePdfBoxDocumentParser()
        );
        System.out.println(document);
    }


    //////////////////////////////////////////////////

    //文档分割器，将大片的文档分割成多个小的文档，更好的进行处理。最好的是向量分割，将文档分割成多个向量，每个向量代表一个文档的一部分
    /**
     * 加载文档并存入向量数据库
     */
    @Test
    public void testReadDocumentAndStore() {
        //使用FileSystemDocumentLoader读取指定目录下的知识库文档
        //并使用默认的文档解析器对文档进行解析(TextDocumentParser)
        Document document = FileSystemDocumentLoader.loadDocument("C:/Users/wangjj/Desktop/knowledge/人工智能.md",
                new TextDocumentParser());
                //为了简单起见，我们暂时使用基于内存的向量存储模型1--embeddingStore
                //InMemoryEmbeddingStore是一个基于内存的向量存储，它将每个文本片段的向量存储在内存中。
                InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

        /**
         * //ingest（）方法--底层执行的是三个步骤：
         * //1、分割文档：默认使用递归分割器，将文档分割为多个文本片段，每个片段包含不超过 300个token，并且有 30个token的重叠部分保证连贯性
         * //DocumentByParagraphSplitter(DocumentByLineSplitter(DocumentBySentenceSplitter(DocumentByWordSplitter)))
         */
        /**
         * //2、文本向量化：使用一个LangChain4j内置的轻量化向量模型对每个文本片段进行向量化
         * //3、将原始文本和向量存储到向量数据库中(InMemoryEmbeddingStore)
         */
        EmbeddingStoreIngestor.ingest(document, embeddingStore);
        //查看向量数据库内容
        System.out.println(embeddingStore);
    }

    /**
     * 自定义分割器
     */
    @Test
    public void testDocumentSplitter() {
        //使用FileSystemDocumentLoader读取指定目录下的知识库文档
//并使用默认的文档解析器对文档进行解析(TextDocumentParser)
        Document document = FileSystemDocumentLoader.loadDocument("C:/Users/wangjj/Desktop/knowledge/人工智能.md",new TextDocumentParser());
                //为了简单起见，我们暂时使用基于内存的向量存储
                InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
        /**
         *自定义文档分割器
         * //按段落分割文档：每个片段包含不超过 300个token，并且有 30个token的重叠部分保证连贯性
         * //注意：当段落长度总和小于设定的最大长度时，就不会有重叠的必要。
         */
        DocumentByParagraphSplitter documentSplitter = new DocumentByParagraphSplitter(
                300,
                30,
                //token分词器：按token计算，30个token为一个单词，每个单词用空格分隔
                new HuggingFaceTokenizer());
        //按字符计算的分割器
        //DocumentByParagraphSplitter documentSplitter = newDocumentByParagraphSplitter(300, 30);

        //构造一个EmbeddingStoreIngestor对象，用于将文档分割成多个向量（调用自定义文档分割器documentSplitter），并将向量存储到向量数据库中embeddingStore
        EmbeddingStoreIngestor
                .builder()
                .embeddingStore(embeddingStore)
                .documentSplitter(documentSplitter)
                .build()
                .ingest(document);//调用ingest方法，将文档分割成多个向量，并将向量存储到向量数据库中
    }


}
